package com.syf.starter.core.netty;

import com.syf.core.engine.SyFrameContext;
import com.syf.starter.config.SyHttpServerConfiguration;
import com.syf.starter.core.netty.handle.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SyNettyHttpServer extends SyAbstractNettyServer {

    private final SyHttpServerConfiguration configuration;

    private final SyFrameContext syFrameContext;

    public SyNettyHttpServer(SyHttpServerConfiguration configuration, SyFrameContext syFrameContext) {
        this.configuration = configuration;
        this.syFrameContext = syFrameContext;
    }

    @Override
    public ChannelInitializer buildChannelInitializer() {
        final IPCheckHandle ipCheckHandle = new IPCheckHandle(configuration.getBlackIpPatterns(), configuration.getWhiteIpPatterns());

        // 构建抗DOS防护handle
        PreventDoSAttackHandle preventDoSAttackHandle = null;
        if (configuration.getEnablePreventDoS()) {
            preventDoSAttackHandle = new PreventDoSAttackHandle(configuration.getDOS_ATTACK_THRESHOLD(), configuration.getDOS_CALS_TIME_WINDOW_UNIT());
        }
        final PreventDoSAttackHandle finalPreventDoSAttackHandle = preventDoSAttackHandle;

        // 构建抗XSS防护handle
        HttpXssFilterHandle xssFilterHandle = null;
        if (configuration.getEnableXssFilter()) {
            xssFilterHandle = new HttpXssFilterHandle();
        }
        final HttpXssFilterHandle finalXssFilterHandle = xssFilterHandle;

        // 构建service invoke Handle
        final HttpServerHandle httpServerHandle = new HttpServerHandle(configuration, syFrameContext.getServiceInvoker());

        return new ChannelInitializer() {
            @Override
            protected void initChannel(Channel channel) throws Exception {
                ChannelPipeline pipeline = channel.pipeline();

                // ip 黑名单和白名单
                pipeline.addLast(ipCheckHandle);

                // server发现空闲连接，主动断开
                pipeline.addLast(new ServerIdleHandle(configuration.getServerName(), 30));

                // 抗DOS防护
                if (finalPreventDoSAttackHandle != null) {
                    pipeline.addLast(finalPreventDoSAttackHandle);
                }

                // 报文编解码
                pipeline.addLast("http-decoder", new HttpRequestDecoder());
                // 添加HttpObjectAggregator解码器，作用是将多个消息转换为单一的FullHttpRequest或者FullHttpResponse
                pipeline.addLast("http-aggregator", new HttpObjectAggregator(1048576)); // 1 MB
                // 添加HttpResponseEncoder编码器，对Http响应消息进行编码
                pipeline.addLast("http-encoder", new HttpResponseEncoder());
                // 添加ChunkedWriteHandler处理器，作用是支持异步发送大的码流（例如大的文件传输），但不占用过多的内存，防止发生Java内存溢出错误
                pipeline.addLast("http-chunked", new ChunkedWriteHandler());

                // Xss攻击防护，主要是对特殊字符进行HTML转义
                if (finalXssFilterHandle != null) {
                    pipeline.addLast(finalXssFilterHandle);
                }

                // 添加业务处理handle
                pipeline.addLast(httpServerHandle);
            }
        };
    }
}
